const Fulfilled = "fulfilled"
const Failed = "failed"
const Pendding = "pendding"

class myPromise {
    constructor(fn) {
        this.status = Pendding
        this.value = null
        this.error = null
        this.successCallback = []
        this.failCallback = []

        fn(this.resolve, this.reject)
    }
    resolve = (value) => {
        if(this.status!==Pendding)
            return 

        this.value = value
        this.status = Fulfilled
        while(this.successCallback.length > 0){
            this.successCallback.shift()()
        }
    }

    reject = (error) => {
        if(this.status!==Pendding)
            return 

        this.error = error
        this.status = Failed

        while(this.failCallback.length > 0){
            this.failCallback.shift()()
        }
    }


    then (successCallback, failCallback) {

        successCallback = successCallback || (value => value)
        failCallback = failCallback || (error => { throw error })

        const promise = new myPromise((resolve, reject) => {
            if(this.status === Fulfilled){
                const x = successCallback(this.value)
                this.resolveValue(x, resolve, reject)
            }
    
            if(this.status === Failed){
                failCallback(this.error)
            }
    
            if(this.status === Pendding){
                this.successCallback.push(()=>{
                    const x = successCallback(this.value)
                    this.resolveValue(x, resolve, reject)
                })
    
                this.failCallback.push(()=>{
                    failCallback(this.error)
                })
            }
        })


        return promise
    }


    resolveValue(value, resolve, reject) {
        if(value instanceof myPromise){
            value.then(resolve, reject)
        } else {
            resolve(value)
        }
    }
}



let p = new myPromise((resolve, reject) => {
    setTimeout(()=>{
        resolve("myPromise p")
    }, 1000)
})


p.then(value => {
    console.log("then1: ", value)
}, error => {
    console.log(error)
})


p.then(value => {
    console.log("then2: ", value)

    return new myPromise((resolve, reject) => {
        setTimeout(()=>{
            resolve("myPromise p22")
        }, 1000)
    })
}, error => {
    console.log(error)
}).then(value=>{
    console.log("then2222: ", value)
})

// myPromise.resolve(p).then(value=>{
//     console.log("resolve, ", value)
// })


// let p2 = new myPromise((resolve, reject) => {
//     setTimeout(()=>{
//         resolve("myPromise p2")
//     }, 2000)
// })

// myPromise.all([p, p2]).then(arr => console.log("all", arr))
// myPromise.race([p, p2]).then(value => console.log("race:", value))


// 几种继承的方式，以及和 class 的区别！
// 1、构造函数式：不会继承父类原型链上的属性
// 2、原型链形式：
// （1）继承了父类属性/父类原型链上的属性
// （2）创建子类实例时无法向父类传参，只能在继承时传参
// 3、组合继承：
// （1）继承了父类属性/父类原型链上的属性
// （2）创建子类实例时可以向父类传参
// （3）执行了两次构造函数
// 4、组合寄生继承：
// （1）继承了父类属性/父类原型链上的属性
// （2）创建子类实例时可以向父类传参
// （3）只执行了一次构造函数
function Parent(name){
    this.name = name
}

Parent.prototype.address = "重庆市"

function Son(name, age){
    Parent.call(this, name)
    this.age = age
}

Son.prototype = Object.create(Parent.prototype)
Son.prototype.constructor = Son

Parent.prototype.address = "重庆市1"

const s = new Son("李四", 18)
console.log("s:", s)


// function curry(fn) {
//     const argLength = fn.length
//     let args = []

//     return function _curry (...args1){
//         const args2 = args.concat(args1)

//         if(args2.length < argLength){
//             return _curry(...args2)
//         }

//         return fn.call(this, ...args2)
//     }
// }


// function debounce(fn, wait) {
//     let timer = null
//     return function (...args){
//         timer && clearTimeout(timer)
//         timer = setTimeout(()=> {
//             fn.call(this, ...args)
//         }, wait)
//     }
// }


// const arr = [1,2,3,4,5,6,7,8]
// const target = 11

// function getIndexes (arr, target) {

// }



